Domain is the primary storage access point. It is responsible for:
Building and maintaining storage-wide information, such as persistent model (like reflection in .NET, but specialized for persistent types), database model (tables, indexes and so on), mappings between them CLR types & properties and database entities (tables, columns, etc).
Validating and upgrading the database schema.
Creating Session objects, you can consider it is a Session factory as well.
Note
Domain objects can be used concurrently, as well as any other read-only content available from it (e.g. Domain.Model or Domain.ExtractedSchema).
To create a domain, you must create DomainConfiguration first. And there are several ways of doing this:
In our example we’ll use the 3rd way:
// Loading the configiration from App.config section
var config = DomainConfiguration.Load("Default");
// Modifying it by registering all the types from specified assembly
config.Types.Register(typeof(MyEntity).Assembly);
// And finally building the domain
var domain = Domain.Build(config);
Now we have the Domain object. But to start working with persistent entities, we need a Session instance.
To configure and build a Domain, you can use DomainConfiguration class. It contains a set of options that could be used to customize DataObjects.Net domain-level behavior.
DataObjects.Net supports two alternative ways of providing connection information:
For specifying connection information DataObjects.Net provides support for standard ADO.NET connection string syntax. You can pass provider name and connection string to DomainConfiguration constructor:
var config = new DomainConfiguration("sqlserver",
"Data Source=localhost; Initial Catalog=Tests; " +
"Integrated Security=True; MultipleActiveResultSets=true;");
Possible provider names are sqlserver (used for connecting to Windows Asure Database as well), oracle, postgresql, mysql, firebird and sqlite. Their canonical names can be found in Xtensive.Orm.WellKnown.Provider class.
You can use connection strings in Domain configuration sections of App.config as well:
<domain
name="Default"
provider="sqlserver"
connectionString="Data Source=localhost; Initial Catalog=MyDatabase;Integrated Security=True;"
upgradeMode="Recreate" />
We recommend to use MultipleActiveResultTests parameter in connection string. Since DataObjects.Net supports on-demand materialization, this option allows it to deal with very large result sets. When this option is turned off, DO4 loads every result set completely. If connection URL is used instead of connection string, it is automatically added to underlying connection string.
ConnectionStrings.com provides many connection string examples for various ADO.NET providers.
Connection URL can be passed to DomainConfiguration constructor or by assigning appropriate value to ConnectionUrl property:
var domainConfig = new DomainConfiguration("sqlserver://localhost/MyDatabase");
Alternatively you can specify connection URL in App.config section:
<configuration>
<configSections>
<section name="Xtensive.Orm" type="Xtensive.Orm.Configuration.Elements.ConfigurationSection, Xtensive.Orm" />
</configSections>
<Xtensive.Orm>
<domains>
<domain name="Default" connectionUrl="sqlserver://localhost/MyDatabase" />
</domains>
</Xtensive.Orm>
</configuration>
Any connection URL has the following structure:
protocol://user:password@server/database?parameter=value¶meter=value
Protocol is identical to provider name when using connection string. See previous section for details. Some parts of connection URL are optional, actual values and parameters may vary with each RDBMS. Any additional parameters are passed to underlying ADO.NET provider as is.
By default DataObjects.Net maps all the entities to the default schema for the user specified in connection URL / string (authenticated user). If another schema must be used, you can specify it in DomainConfiguration.DefaultSchema or defaultScema attribute of domain element in App.config section.
Then you must register persistent types that will be used to build persistent model. Use Types collection and its Register method overloads to register single type, namespace or whole assembly. It is recommended to declare all persistent classes in separate namespace, e.g. MyCompany.MyProduct.Model and register all classes in this namespace.
domainConfig.Types.Register(
typeof (Person).Assembly, typeof (Person).Namespace);
<domain
name="Default"
provider="sqlserver"
connectionString="Data Source=localhost; Initial Catalog=MyDatabase; Integrated Security=True;"
upgradeMode="Recreate">
<types>
<add assembly="MyCompany.MyProduct.Model" />
</types>
</domain>
Persistent model can be also separated into several assemblies. In this case all assemblies that contain persistent model should be registered in domain types.
When domain is being built it analyzes existing database structure, and tries to upgrade it to actual model version. UpgradeMode property of DomainUpgradeMode type specifies how this upgrade should be performed. There are several available options:
Default upgrade mode value is PerformSafely.
domainConfig.UpgradeMode = DomainUpgradeMode.Recreate;
NamingConvention property contains a set of rules for naming database structures such as tables, columns, indexes, etc. Several options are available.
NamingRules specifies underscore substitution for special symbols:
By default dots and hypens are not underscored.
LetterCasePolicy specifies name transformation:
NamespacePolicy specifies namespace substitution for persistent entities:
BuildInParallel property allows to enable parallel construction of a Domain. DataObjects.Net tries to minimize time for Domain.Build() by performing certain operations in separate thread. This option is enabled by default. If you for some reason don’t want separate thread to be used you could set this property to false.
ForcedServerVersion property allows to turn compatiblity with a particular version of database server. By default DataObjects.Net detects server version at start-up and uses recent features if they are available.
configuration.ForcedServerVersion = "9.0.0.0";
IncludeSqlInExceptions property allows to control message of exceptions that are thrown when error occurs when executing SQL query. By default query that cause the error is included into exception. You could disable such behavior by setting this property to false.
SchemaSyncExceptionFormat property allows to control message of exceptions that are thrown when database schema is not compatible with expect one. Two options are available:
Domain configuration can be also loaded from application configuration file. To do this you should add DataObjects.Net configuration section in your configuration file. One configuration section can contain several domain configurations, in the following example two domain configurations are declared (“stage” and “production”):
<configSections>
<section
name="Xtensive.Orm"
type="Xtensive.Orm.Configuration.Elements.ConfigurationSection, Xtensive.Orm" />
</configSections>
<Xtensive.Orm>
<domains>
<domain name="stage"
upgradeMode="Recreate"
connectionUrl="sqlserver://localhost/MyStageDatabase">
<types>
<add assembly="MyAssembly" namespace="MyProduct.Model" />
</types>
</domain>
<domain name="production"
upgradeMode="Skip"
connectionUrl="sqlserver://localhost/MyProductionDatabase">
<types>
<add assembly="MyAssembly" namespace="MyProduct.Model" />
</types>
</domain>
</domains>
</Xtensive.Orm>
Domain configuration can be loaded from configuration file with the help of DomainConfiguration.Load() method:
var domainConfig = DomainConfiguration.Load("MyDomain");
Having that done you may change the configuration loaded setting any properties manually:
var domainConfig = DomainConfiguration.Load("default");
domainConfig.UpgradeMode = DomainUpgradeMode.Recreate;
domainConfig.Types.Register(typeof (Person).Assembly, typeof (Person).Namespace);
When domain configuration is ready, we can build domain using Domain.Build() static method:
var domain = Domain.Build(domainConfig);
During the build process DataObjects.Net makes the following steps:
As a result this method will return built and ready to use Domain instance. Its configuration is accessible in read-only mode from Domain.Configuration property.
Domain type exposes 2 events:
Usually SessionOpen event is used to subscribe to various Session events of every newly opened Session instance:
Domain.SessionOpen += (source, args) => {
args.Session.Events.TransactionOpened += TransactionOpened;
args.Session.Events.TransactionCommitting += TransactionCommitting;
...
};